package com.key.util;

/**
 * @Author dzl
 * @Date 2021/12/6 5:10 下午
 * 获取接口实现类
 */

import com.alibaba.fastjson.JSON;

import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.JarURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class ClassUtil {

    /**
     * 获取指定接口的所有实现实例
     *
     * @param c
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public static List<Object> getAllObjectByInterface(Class<?> c)
            throws InstantiationException, IllegalAccessException {
        List<Object> list = new ArrayList<Object>();
        List<Class<?>> classes = getAllClassByInterface(c);
        for (int i = 0; i < classes.size(); i++) {
            list.add(classes.get(i).newInstance());
        }
        return list;
    }

    /**
     * 获取指定接口的实例的Class对象
     *
     * @param c
     * @return
     */
    public static List<Class<?>> getAllClassByInterface(Class<?> c) {
        /*如果传入的参数不是接口直接结束*/
        if (!c.isInterface()) {
            return null;
        }
        List<Class<?>> allClass = null;
        try {
            allClass = getAllClassFromPackage(c);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return allClass;
    }

    /**
     * 根据包名获取所有class
     *
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private static List<Class<?>> getAllClassFromPackage(Class<?> c) {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        /*遍历所有类*/
        try {
            Enumeration<URL> enumeration = classLoader.getResources("");
            List<Class<?>> classNames = getClassNames(enumeration, c);
            return classNames;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * @param enumeration
     * @param c           接口
     * @return
     */
    private static List<Class<?>> getClassNames(Enumeration<URL> enumeration, Class<?> c) {
        List<Class<?>> classList = new ArrayList<>();
        while (enumeration.hasMoreElements()) {
            List<String> classNames = null;
            URL url = enumeration.nextElement();
            if (url != null) {
                String type = url.getProtocol();
                if (type.equals("file")) {
                    String fileSearchPath = url.getPath();
                    /*判断是否是资源路径*/
                    if (fileSearchPath.contains("META-INF")) {
                        continue;
                    }
                    classNames = getClassNameByFile(fileSearchPath);
                } else if (type.equals("jar")) {
                    String fileSearchPath = url.getPath();
                    System.out.println(fileSearchPath);
                    try {
                        JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection();
                        JarFile jarFile = jarURLConnection.getJarFile();
                        classNames = getClassNameByJar(jarFile);
                    } catch (Exception e) {
                        continue;
                    }
                }
                /*遍历需要的class*/
                if (classNames != null) {
                    for (String x : classNames) {
                        try {
                            System.out.println(x);
                            Class<?> aClass = Class.forName(x);
                            if (c.isAssignableFrom(aClass)) {
                                classList.add(aClass);
                            }
                        } catch (Exception e) {
                            continue;
                        }

                    }
                }
            }

        }
        System.out.println(JSON.toJSONString(classList));
        return classList;
    }

    /**
     * 获取项目某路径下的所有类
     *
     * @param fileSearchPath
     * @return
     */
    private static List<String> getClassNameByFile(String fileSearchPath) {
        List<String> classNames = new ArrayList<>();
        File file = new File(fileSearchPath);
        File[] childFiles = file.listFiles();
        for (File childFile : childFiles) {
            if (childFile.isDirectory()) {
                classNames.addAll(getClassNameByFile(childFile.getPath()));
            } else {
                String childFilePath = childFile.getPath();
                if (childFilePath.endsWith(".class")) {
                    String className = childFilePath.substring(childFilePath.lastIndexOf("classes") + 8).replaceAll("/", ".");
                    className = className.substring(0, className.indexOf(".class"));
                    classNames.add(className);
                }
            }
        }

        return classNames;
    }

    /**
     * 从jar包中获取某路径下的所有类
     *
     * @param jarFile
     * @return
     */
    private static List<String> getClassNameByJar(JarFile jarFile) {
        List<String> classNames = new ArrayList<>();
        Enumeration<JarEntry> entrys = jarFile.entries();
        while (entrys.hasMoreElements()) {
            JarEntry jarEntry = entrys.nextElement();
            String entryName = jarEntry.getName();
            if (entryName.endsWith(".class")) {
                String className = entryName.replace("/", ".");
                className = className.substring(0, className.indexOf(".class"));
                classNames.add(className);
            }

        }
        return classNames;
    }
}
